package tool

import java.io.{File, FileFilter}
import java.nio.file.Files

import command.CommandExec
import dao._
import javax.inject.Inject
import org.apache.commons.io.FileUtils
import org.joda.time.DateTime
import play.api.data._
import play.api.data.Forms._
import play.api.data.format.Formats.doubleFormat
import play.api.mvc.{MultipartFormData, Request, RequestHeader}
import utils.Utils

import scala.collection.JavaConverters._
import models.Tables._
import play.api.libs.Files.TemporaryFile
import play.api.libs.json.Json

import implicits.Implicits._
import shared.VarTool
import tool.Pojo.CommandData


/**
 * Created by yz on 2018/5/10
 */
class Tool @Inject()(modeDao: ModeDao) {

  case class DownloadData(sampleName: String, kind: String)

  val downloadForm = Form(
    mapping(
      "sampleName" -> text,
      "kind" -> text
    )(DownloadData.apply)(DownloadData.unapply)
  )

  case class HeatmapData(method: String, rowDist: String, colDist: String, rowCluster: String, colCluster: String)

  val heatmapForm = Form(
    mapping(
      "method" -> text,
      "rowDist" -> text,
      "colDist" -> text,
      "rowCluster" -> text,
      "colCluster" -> text
    )(HeatmapData.apply)(HeatmapData.unapply)
  )

  case class KeggEnrichData(geneId: String, method: String, fdr: String, cutoff: String, pValue: String)

  val keggEnrichForm = Form(
    mapping(
      "geneId" -> text,
      "method" -> text,
      "fdr" -> text,
      "cutoff" -> text,
      "pValue" -> text
    )(KeggEnrichData.apply)(KeggEnrichData.unapply)
  )

  case class GoEnrichData(geneId: String, twa: String, ewa: String)

  val goEnrichForm = Form(
    mapping(
      "geneId" -> text,
      "twa" -> text,
      "ewa" -> text
    )(GoEnrichData.apply)(GoEnrichData.unapply)
  )

  case class NormalData(normalMethod: Option[Seq[Int]], colName: String, coefficient: Double)

  val normalForm = Form(
    mapping(
      "normalMethod" -> optional(seq(number)),
      "colName" -> text,
      "coefficient" -> of(doubleFormat)
    )(NormalData.apply)(NormalData.unapply)
  )

  case class DataDealData(normal: Option[String], delete: Option[String], replace: Option[String])

  val dataDealForm = Form(
    mapping(
      "normal" -> optional(text),
      "delete" -> optional(text),
      "replace" -> optional(text)
    )(DataDealData.apply)(DataDealData.unapply)
  )

  case class DeleteData(iqr: Double)

  val deleteForm = Form(
    mapping(
      "iqr" -> of(doubleFormat)
    )(DeleteData.apply)(DeleteData.unapply)
  )

  case class ReplaceData(replaceMethod: String, rate: Double, assignValue: String, kValue: Int)

  val replaceForm = Form(
    mapping(
      "replaceMethod" -> text,
      "rate" -> of(doubleFormat),
      "assignValue" -> text,
      "kValue" -> number
    )(ReplaceData.apply)(ReplaceData.unapply)
  )

  case class GeneIdStrData(geneIdStr: String)

  val geneIdStrForm = Form(
    mapping(
      "geneIdStr" -> text
    )(GeneIdStrData.apply)(GeneIdStrData.unapply)
  )

  case class HClusterData(method: String, sampleDist: String, sampleCluster: String)

  val hClusterForm = Form(
    mapping(
      "method" -> text,
      "sampleDist" -> text,
      "sampleCluster" -> text
    )(HClusterData.apply)(HClusterData.unapply)
  )

  val groupingNameFom = Form(
    single(
      "groupingName" -> text
    )
  )

  case class RocData(groupingName: String, pGroup: String)

  val rocForm = Form(
    mapping(
      "groupingName" -> text,
      "pGroup" -> text
    )(RocData.apply)(RocData.unapply)
  )

  case class GroupMessage(groupingName: String, groupNames: Seq[String],
                          sampleNames: Seq[String])

  val groupForm = Form(
    mapping(
      "groupingName" -> text,
      "groupNames" -> seq(text),
      "sampleNames" -> seq(text)
    )(GroupMessage.apply)(GroupMessage.unapply)
  )

  case class RelationData(id: Int, group1SampleNames: Seq[String], group2SampleNames: Seq[String])

  val relationForm = Form(
    mapping(
      "id" -> number,
      "group1SampleNames" -> seq(text),
      "group2SampleNames" -> seq(text)
    )(RelationData.apply)(RelationData.unapply)
  )

  case class GroupData(groupName: String)

  val groupNameForm = Form(
    mapping(
      "groupName" -> text
    )(GroupData.apply)(GroupData.unapply)
  )


  case class GoBarData(terms: Seq[String], datas: Seq[String], kinds: Seq[String])

  val goBarForm = Form(
    mapping(
      "terms" -> seq(text),
      "datas" -> seq(text),
      "kinds" -> seq(text)
    )(GoBarData.apply)(GoBarData.unapply)
  )

  case class BarData(terms: Seq[String], datas: Seq[String])

  val barForm = Form(
    mapping(
      "terms" -> seq(text),
      "datas" -> seq(text)
    )(BarData.apply)(BarData.unapply)
  )

  case class ExpressPatternData(sampleNameStr: String, method: String, cMethod: String, pTree: String, kTree: String,
                                k: String, sampleDist: String, sampleCluster: String)

  val expressPatternForm = Form(
    mapping(
      "sampleNameStr" -> text,
      "method" -> text,
      "cMethod" -> text,
      "pTree" -> text,
      "kTree" -> text,
      "k" -> text,
      "sampleDist" -> text,
      "sampleCluster" -> text
    )(ExpressPatternData.apply)(ExpressPatternData.unapply)
  )

  def getPepFile(sampleName: String) = {
    new File(Tool.dataFile, s"${sampleName}.pep.fa")
  }

  def getGffFile(sampleName: String) = {
    new File(Tool.dataFile, s"${sampleName}.gff")
  }

  def getUserId(implicit request: RequestHeader) = {
    request.session.get("id").get.toInt
  }

  def getUserMissionDir(implicit request: RequestHeader) = {
    val userIdDir = getUserIdDir
    new File(userIdDir, "mission")
  }

  def getUserIdDir(implicit request: RequestHeader) = {
    val userId = getUserId
    new File(Tool.userDir, userId.toString)
  }

  def generateMissionName = {
    (new DateTime).toString("yyyy_MM_dd_HH_mm_ss")
  }

  def getSampleName(str: String) = {
    val r = ".*\\((.*)\\).*".r
    val r(sampleName) = str
    sampleName
  }

  def getSeqMap(file: File) = {
    val lines = Utils.file2Lines(file)
    lines.zipWithIndex.filter { case (line, i) =>
      line.startsWith(">")
    }.map { case (line, i) =>
      val id = line.drop(1).split("\\s+")(0)
      val seq = lines.drop(i + 1).takeWhile(!_.startsWith(">")).mkString
      (id, seq)
    }.toMap

  }

}

object Tool extends ProjectTool with ProjectFileTool {


  val dbName = "vg_p3_database"
  val windowsPath = s"C:\\${dbName}"
  val playPath = new File("../").getAbsolutePath
  val linuxPath = playPath + s"/${dbName}"
  val isWindows = {
    if (new File(windowsPath).exists()) true else false
  }
  val path = {
    if (new File(windowsPath).exists()) windowsPath else linuxPath
  }
  val userDir = new File(path, "user")

  val dataFile = new File(path, "data")
  val proteinDir = new File(dataFile, "protein")
  val exampleDir = new File(path, s"example")
  val binPath = new File(path, "bin")

  val keggDir = new File(binPath, "kegg")
  val pfamDir = new File(binPath, "pfam")
  val assembleDir = new File(binPath, "assemble")

  val wsl = if (isWindows) "wsl" else ""
  val annoDir = new File(binPath, "Anno")
  val orthoMclDir = new File(binPath, "ORTHOMCLV1.4")
  val mummer = new File("/mnt/sdb/linait/tools/quickmerge/MUMmer3.23/")
  val blastFile = new File(binPath, "ncbi-blast-2.6.0+/bin/blastn")
  val blastpFile = new File(binPath, "ncbi-blast-2.6.0+/bin/blastp")
  val blastxFile = new File(binPath, "ncbi-blast-2.6.0+/bin/blastx")
  val condaBinPath = "/root/anaconda3/bin/"
  val blast2HtmlFile = new File(binPath, "blast2html-82b8c9722996/blast2html.py")
  val svBin = new File(binPath, "SV_finder_2.2.1/bin")
  val rPath = {
    val rPath = "C:\\workspaceForIDEA\\p3bacter\\rScripts"
    val linuxRPath = linuxPath + "/rScripts"
    if (new File(rPath).exists()) rPath else linuxRPath
  }
  val windowsTestDir = new File("C:\\temp")
  val linuxTestDir = new File(playPath, "workspace")
  val testDir = if (windowsTestDir.exists()) windowsTestDir else linuxTestDir
  val crisprDir = new File(binPath, s"CRISPRCasFinder")
  val vmatchDir = new File(binPath, s"vmatch-2.3.0-Linux_x86_64-64bit")
  val muscleCommand = {
    "muscle"
  }

  val Rscript = {
    "Rscript"
  }

  val pyPath = {
    val path = "C:\\workspaceForIDEA\\p3_platform\\server\\pyScripts"
    val linuxPyPath = linuxPath + "/pyScripts"
    if (isWindows) new File(path) else new File(linuxPyPath)
  }

  def getMissionIdDirById(missionId: Int)(implicit request: RequestHeader) = {
    val userMissionFile = getUserMissionDir
    new File(userMissionFile, missionId.toString)
  }

  def fileMoveDir(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    fileMoveDirOp(fieldName, dir).get
  }

  def fileMoveDirOp(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    val tempFile = request.body.file(fieldName).get
    if (tempFile.ref.path.toFile.length() > 0) {
      val destFile = new File(dir, tempFile.filename)
      tempFile.ref.moveTo(destFile, replace = true)
      Some(destFile)
    } else None
  }

  def fileMoveDirs(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    fileMoveDirsOp(fieldName, dir).filter(_.isDefined).map(_.get)
  }

  def fileMoveDirsOp(fieldName: String, dir: File)(implicit request: Request[MultipartFormData[TemporaryFile]]) = {
    request.body.files.toList.filter(x => x.key == fieldName).map { tempFile =>
      if (tempFile.ref.path.toFile.length() > 0) {
        val destFile = new File(dir, tempFile.filename)
        tempFile.ref.moveFileTo(destFile, replace = true)
        Some(destFile)
      } else None
    }
  }

  def changeGbffFilesSuffix(files: List[File], tmpDir: File) = {
    files.foreach { file =>
      val destFile = new File(tmpDir, s"${file.getName.fileNamePrefix}.gbff")
      if (!destFile.exists()) file.copyTo(destFile)
    }
  }

  def createTempDirectory(prefix: String)(implicit modeDao: ModeDao) = {
    if (isTestMode) Tool.testDir else Files.createTempDirectory(prefix).toFile
  }

  def deleteDirectory(direcotry: File)(implicit modeDao: ModeDao) = {
    if (!isTestMode) Utils.deleteDirectory(direcotry)
  }

  def isTestMode(implicit modeDao: ModeDao) = {
    val mode = Utils.execFuture(modeDao.select)
    if (mode.test == "t") true else false
  }

  def getGbffFiles(tmpDir: File) = {
    tmpDir.listFiles().toList.filter(_.getName.endsWith(".gbff"))
  }

  def readGeneBanks(parentWorkspaceDir: File) = {
    val pyFile = new File(Tool.pyPath, "readGenBank.py")
    val gbffFiles = Tool.getGbffFiles(parentWorkspaceDir)
    val workspaceDir = Tool.getReadGeneWorkspaceDir(parentWorkspaceDir)
    gbffFiles.foreach(_.fileCopyToDir(workspaceDir))
    val commands = gbffFiles.map { gbffFile =>
      s"""
         |python3 ${pyFile.unixPath} -i ${gbffFile.unixPath}
         |""".stripMargin
    }
    CommandData(workspaceDir, commands)
  }

  def genePredicts(parentWorkspaceDir: File) = {
    val gbffFiles = Tool.getGbffFiles(parentWorkspaceDir)
    val workspaceDir = Tool.getGenePredictDir(parentWorkspaceDir)
    val readGeneDir = Tool.getReadGeneWorkspaceDir(parentWorkspaceDir)
    val commands = gbffFiles.map { gbffFile =>
      val prefix = gbffFile.namePrefix
      val geneInfoFile = new File(readGeneDir, s"${prefix}_geneInfo.txt")
      val geneInfoLines = geneInfoFile.txtLines.drop(1)
      val infoFile = new File(readGeneDir, s"${prefix}_info.txt")
      val infoLines = infoFile.txtLines.drop(1)
      val columns = infoLines.head
      val kind = columns(8)
      if (geneInfoLines.isEmpty) {
        Tool.getGenomeFile(readGeneDir, prefix).fileCopyToDir(workspaceDir)
        s"""
           |perl ${Utils.dosPath2Unix(Tool.binPath)}/01.Gene-prediction/bin/gene-predict_v2.pl --SpeType B --SampleId ${prefix} --genemark --verbose -shape ${kind} --cpu 10  --run multi -outdir output ${Tool.getGenomeFile(workspaceDir, prefix).unixPath}
           |cp ${workspaceDir.unixPath}/output/final/${prefix}.cds ${workspaceDir.unixPath}/${prefix}.cds.fa
           |cp ${workspaceDir.unixPath}/output/final/${prefix}.pep ${workspaceDir.unixPath}/${prefix}.pep.fa
           |cp ${workspaceDir.unixPath}/output/final/${prefix}.gff ${workspaceDir.unixPath}/
             """.stripMargin
      } else ""
    }
    CommandData(workspaceDir, commands)
  }

  def getReadGeneWorkspaceDir(parentWorkpaceDir: File) = {
    new File(parentWorkpaceDir, s"read_gene")
  }

  def getGenePredictDir(parentWorkpaceDir: File) = {
    new File(parentWorkpaceDir, s"gene_predict")
  }

  def getUserMissionDir(userId: Int) = {
    val userIdDir = getUserIdDir(userId)
    new File(userIdDir, "mission")
  }

  def getResultDirById(missionId: Int)(implicit request: RequestHeader) = {
    val missionIdDir = getMissionIdDirById(missionId)
    new File(missionIdDir, "result")
  }

  def getConfigFile(dir: File) = {
    new File(dir, s"config.txt")
  }

  def getUserMissionDir(implicit request: RequestHeader) = {
    val userIdDir = getUserIdDir
    new File(userIdDir, "mission")
  }

  def getUserId(implicit request: RequestHeader) = {
    request.session.get("id").get.toInt
  }

  def getUserIdDir(implicit request: RequestHeader) = {
    val userId = getUserId
    new File(Tool.userDir, userId.toString)
  }

  def getUserIdDir(userId: Int) = {
    new File(Tool.userDir, userId.toString)
  }

  def getCdsFile(workspaceDir: File, sampleName: String) = {
    new File(workspaceDir, s"${sampleName}.cds.fa")
  }

  def getPepFile(workspaceDir: File, sampleName: String) = {
    new File(workspaceDir, Tool.getPepFileName(sampleName))
  }

  def getPepFileName(sampleName: String) = {
    s"${sampleName}.fa"
  }

  def getLogFile(dir: File) = {
    val file = new File(dir, "log.txt")
    "Run successfully!".toFile(file)
    file
  }

  def getGenomeFile(sampleName: String) = {
    new File(Tool.dataFile, s"${sampleName}.genome.fa")
  }

  def getGenomeFile(dir: File, prefix: String) = {
    new File(dir, Tool.getGenomeFileName(prefix))
  }

  def getGenomeFileName(prefix: String) = {
    s"${prefix}.genome.fa"
  }

  def dealMissFile(file: File) = {
    val lines = FileUtils.readLines(file).asScala
    val newLines = lines.map { line =>
      val columns = line.split("\t")
      s"${columns(0)}\t${columns(2)}"
    }
    FileUtils.writeLines(file, newLines.asJava)
  }

  def svAnno(file: File, dbFile: File) = {
    case class CDSInfo(proteinId: String, start: Int, end: Int)
    val dbLines = Utils.file2Lines(dbFile)
    val map = dbLines.filter(_.startsWith(">")).map { line =>
      val columns = line.drop(1).split("\\s+")
      val infos = columns(1).replaceAll("^locus=", "").split(":")
      (infos(0), CDSInfo(columns(0), infos(1).toInt, infos(2).toInt))
    }.groupBy(_._1).mapValues(x => x.map(_._2).sortBy(_.start))
    val lines = Utils.file2Lines(file)
    val newLines = lines.map { line =>
      val columns = line.split("\t")
      val seqName = columns(0)
      val infos = map(seqName)
      val start = columns(1).toInt
      val end = columns(2).toInt
      val proteinIds = infos.filterNot { info =>
        info.end < start || info.start > end
      }.map(_.proteinId)
      val proteinIdStr = if (proteinIds.isEmpty) "NA" else proteinIds.mkString(",")
      s"${line}\t${proteinIds.size}\t${proteinIdStr}"
    }
    Utils.lines2File(new File(file.getParent, "sv.anno.txt"), newLines)
  }

  def mummer(workspaceDir: File, resultDir: File) = {
    val configFile = new File(workspaceDir, "config.txt")
    val configJson = Json.parse(configFile.str)
    val querySampleName = (configJson \ "querySampleName").as[String]
    val refSampleName = (configJson \ "refSampleName").as[String]
    val genePredictDir = Tool.getGenePredictDir(workspaceDir)
    val readGeneDir = Tool.getReadGeneWorkspaceDir(workspaceDir)
    List(readGeneDir, genePredictDir).foreach { dir =>
      dir.listFiles().filter { file =>
        List(VarTool.genomeFileSuffix, VarTool.gffFileSuffix, VarTool.cdsFileSuffix).exists(y => file.getName.endsWith(y))
      }.foreach { file =>
        file.fileCopyToDir(workspaceDir)
      }
    }
    val fileStr = List(refSampleName, querySampleName).map { sampleName =>
      val file = Tool.getGenomeFile(workspaceDir, sampleName)
      file.getName
    }.mkString(" ")
    val command =
      s"""
         |perl ${Tool.svBin.unixPath}/SV_finder.pl ${fileStr} --prefix data --tfix ${refSampleName} --qfix ${querySampleName} --nocomp --outdir output --locate
         |cp output/Result/01.Synteny/Target-Query.parallel.png  ${resultDir.unixPath}/Target-Query.parallel.png
         |cp output/Result/01.Synteny/Target-Query.parallel.svg ${resultDir.unixPath}/Target-Query.parallel.svg
         |cp output/Result/01.Synteny/Target-Query.xoy.png ${resultDir.unixPath}/Target-Query.xoy.png
         |cp output/Result/01.Synteny/Target-Query.xoy.svg ${resultDir.unixPath}/Target-Query.xoy.svg
         |cp output/Result/01.Synteny/data.axt  ${resultDir.unixPath}/axt.txt
         |cp output/Result/01.Synteny/data.alg  ${resultDir.unixPath}/alg.txt
         |cp output/Result/01.Synteny/data.que.miss ${resultDir.unixPath}/query.miss.txt
         |cp output/Result/01.Synteny/data.tar.miss ${resultDir.unixPath}/target.miss.txt
         |cp output/Result/01.Synteny/data.cover ${resultDir.unixPath}/cover.txt
         |cp output/Result/01.Synteny/data.identity.list ${resultDir.unixPath}/identity_list.txt
         |cp output/Result/02.Variation/data.indel ${resultDir.unixPath}/indel.txt
         |cp output/Result/02.Variation/data.snp ${resultDir.unixPath}/snp.txt
         |cp output/Result/02.Variation/data.sv ${resultDir.unixPath}/sv.txt
         |cp output/Result/02.Variation/SV_cycle.svg ${resultDir.unixPath}/SV_cycle.svg
         |cp output/Result/02.Variation/SV_cycle.png ${resultDir.unixPath}/SV_cycle.png
         |cp output/Result/02.Variation/final.snp_indel.dis.png ${resultDir.unixPath}/final.snp_indel.dis.png
         |cp output/Result/02.Variation/final.snp_indel.dis.svg ${resultDir.unixPath}/final.snp_indel.dis.svg
         |cp output/Result/02.Variation/data.snp ${workspaceDir.unixPath}/snp.txt
         |python ${Tool.pyPath.unixPath}/dealSnp.py -q ${querySampleName}
         |perl  ${Tool.binPath.unixPath}/09.Snp/src/snp_annotation_v2.2.pl snp_out.txt ${refSampleName}.genome.fa ${refSampleName}.gff --prefix data --outdir snp_anno --code 11
         |cp  snp_anno/data.cds.axt.txt ${resultDir.unixPath}/snp.cds.axt.txt
         |cp  snp_anno/data.cds.info.xls ${resultDir.unixPath}/snp.cds.info.xls
         |cp  snp_anno/data.cds.stat.xls ${resultDir.unixPath}/snp.cds.stat.xls
         |cp  snp_anno/data.chr.stat.xls ${resultDir.unixPath}/snp.chr.stat.xls
         |cp  snp_anno/data.intergenic.info.xls ${resultDir.unixPath}/snp.intergenic.info.xls
         |cp output/Result/02.Variation/data.indel ${workspaceDir.unixPath}/indel.txt
         |python ${Tool.pyPath.unixPath}/dealIndel.py
         |perl  ${Tool.binPath.unixPath}/10.InDel/src/indel_annotation_v2.pl indel_out.txt ${refSampleName}.genome.fa ${refSampleName}.gff --prefix data --outdir indel_anno --sis --code 11
         |cp  indel_anno/data.len.svg ${resultDir.unixPath}/indel.len.svg
         |cp  indel_anno/data.cds.axt ${resultDir.unixPath}/indel.cds.axt.txt
         |cp  indel_anno/data.cdsindel.stat ${resultDir.unixPath}/indel.cdsindel.stat.xls
         |cp  indel_anno/data.cds.stat ${resultDir.unixPath}/indel.cds.stat.xls
         |cp  indel_anno/data.chr.stat ${resultDir.unixPath}/indel.chr.stat.xls
         |cp  indel_anno/data.info ${resultDir.unixPath}/indel.info.xls
         |cp  indel_anno/data.intergenic.info ${resultDir.unixPath}/indel.intergenic.info.xls
         |cp  indel_anno/data.len.dis ${resultDir.unixPath}/indel.len.dis.xls
       """.stripMargin
    CommandData(workspaceDir, List(command))
  }

  def orthoMcl(workspaceDir: File, resultDir: File) = {
    val configFile = new File(workspaceDir, "config.txt")
    val configJson = Json.parse(configFile.str)
    val gbffFiles = Tool.getGbffFiles(workspaceDir)
    val data = FormTool.orthoMclForm.bind(configJson).get
    val genePredictDir = Tool.getGenePredictDir(workspaceDir)
    val readGeneDir = Tool.getReadGeneWorkspaceDir(workspaceDir)
    val filePrefixs = gbffFiles.map { file =>
      file.namePrefix
    }
    List(readGeneDir, genePredictDir).foreach { dir =>
      dir.listFiles().filter(_.getName.endsWith(VarTool.pepFileSuffix)).foreach { file =>
        val destFile = new File(workspaceDir, s"${file.getName.replaceAll(s"${VarTool.pepFileSuffix}$$", ".fa")}")
        file.copyTo(destFile)
      }
    }
    val fileStr = filePrefixs.map { filePrefix =>
      s"${filePrefix}.fa"
    }.mkString(",")

    val command =
      s"""
         |perl  ${Tool.orthoMclDir.unixPath}/orthomcl.pl --mode 1 --fa ${fileStr} --pi_cutoff ${data.piCutoff} --pv_cutoff ${data.pvCutoff} --pmatch_cutoff ${data.pmatchCutoff}
         |perl ${Tool.binPath.unixPath}/Compare-rna/select_ortholog_gene_pro.pl fa.list all_orthomcl.out
         |cp all_orthomcl.out ${resultDir.unixPath}/all_orthomcl.out
         |cp gene.family.info.xls ${resultDir.unixPath}/gene.family.info.xls
         |cp genefamily.strain.mat.xls ${resultDir.unixPath}/genefamily.strain.mat.xls
       """.stripMargin
    CommandData(workspaceDir, List(command))
  }

  def mummerResultDeal(workspaceDir: File, resultDir: File) = {
    val configFile = new File(workspaceDir, "config.txt")
    val configJson = Json.parse(configFile.str)
    Tool.dealMissFile(new File(resultDir, "query.miss.txt"))
    Tool.dealMissFile(new File(resultDir, "target.miss.txt"))
    val file = new File(resultDir, "sv.txt")
    val lines = file.txtLines
    val newLines = lines.map { columns =>
      columns.init
    }
    newLines.toTxtFile(file)
    Utils.svg2png(new File(resultDir, "indel.len.svg"))
    val refSampleName = (configJson \ "refSampleName").as[String]
    Tool.svAnno(new File(resultDir, "sv.txt"), Tool.getCdsFile(workspaceDir, refSampleName))
  }

  def phyTree(workspaceDir: File, resultDir: File) = {
    val configFile = new File(workspaceDir, "config.txt")
    val configJson = Json.parse(configFile.str)
    val refSampleName = (configJson \ "refSampleName").as[String]
    val file = Tool.getGenomeFile(workspaceDir, refSampleName)
    val sampleNames = (configJson \ "sampleNames").as[List[String]]
    val genePredictDir = Tool.getGenePredictDir(workspaceDir)
    val readGeneDir = Tool.getReadGeneWorkspaceDir(workspaceDir)
    List(readGeneDir, genePredictDir).foreach { dir =>
      dir.listFiles().filter(_.getName.endsWith(VarTool.genomeFileSuffix)).foreach { file =>
        file.fileCopyToDir(workspaceDir)
      }
    }
    val firstLine = s"ref=${Tool.getGenomeFileName(refSampleName)}"
    val lines = sampleNames.map { sampleName =>
      s"${sampleName}=${Tool.getGenomeFileName(sampleName)}"
    }
    (firstLine :: lines).toFile(new File(workspaceDir, "seq.list"))
    val command =
      s"""
         |dos2unix *
         |perl ${Tool.binPath.unixPath}/09.Snp/src/find_repeat_for_bac_snp.pl  --ref ${file.getName} -out dup.out
         |perl ${Tool.binPath.unixPath}/09.Snp/src/MUMmerSnpPipline.V2.3.pl -lib seq.list -dup dup.out -dir out -readlist reads_info.list -pileup_q 20 -pileup_e 5 -pileup_n 10
         |perl ${Tool.binPath.unixPath}/13.Phylogenetic_tree/src/snp2fa_v2.pl out/clean.snp.pileup2 all.mfa ${refSampleName}
         |perl ${Tool.binPath.unixPath}/13.Phylogenetic_tree/src/02.phylogeny/bin/phylo_tree.pl all.mfa -format mfa -type ml -b '-4' -d nt -outdir treeOut
         |cp treeOut/tree.png ${resultDir.unixPath}/
         |cp treeOut/tree.newick ${resultDir.unixPath}/
         |cp treeOut/tree.svg ${resultDir.unixPath}/
         |cp treeOut/tree.root.svg ${resultDir.unixPath}/
               """.stripMargin
    CommandData(workspaceDir, List(command))
  }

  def getSeqFile(dir: File) = {
    new File(dir, "seq.fa")
  }


  def crispr(workspaceDir: File, resultDir: File) = {
    val configFile = new File(workspaceDir, "config.txt")
    val configJson = Json.parse(configFile.str)
    val data = FormTool.crisprForm.bind(configJson).get
    val seqFile = Tool.getSeqFile(workspaceDir)
    val basicCommands = List(s"export PATH=$$PATH:/${Tool.vmatchDir.unixPath}\n", s"perl ${Tool.crisprDir.unixPath}/CRISPRCasFinder.pl -in ${seqFile.unixPath} -out ${resultDir.unixPath}/out -so ${Tool.vmatchDir.unixPath}/SELECT/sel392v2.so " +
      s"-drpt ${Tool.crisprDir.unixPath}/supplementary_files/repeatDirection.tsv -rpts ${Tool.crisprDir.unixPath}/supplementary_files/Repeat_List.csv " +
      s"-minDR ${data.minDR} -maxDR ${data.maxDR} -percSPmin ${data.percSPmin} -percSPmax ${data.percSPmax} " +
      s"-spSim ${data.spSim} -mismDRs ${data.mismDRs}  -truncDR ${data.truncDR} -flank ${data.flank} " +
      s"-cf ${Tool.crisprDir.unixPath}/CasFinder-2.0.2 ")
    val armCommand = if (data.arm.isEmpty) "-noMism" else ""
    val dtCommand = if (data.dt.isDefined) "-betterDetectTrunc" else ""
    val casCommands = if (data.cas.isDefined) {
      val inCommands = List("-cas -rcfowce ", s"-def ${data.defValue}")
      val metaCommand = if (data.meta.isDefined) "-meta" else ""
      inCommands ::: List(metaCommand)
    } else List[String]()
    val commands = List((basicCommands ::: List(armCommand, dtCommand) ::: casCommands).mkString(" "))
    CommandData(workspaceDir, commands)
  }

  def vfdb(workspaceDir: File, resultDir: File) = {
    val configFile = new File(workspaceDir, "config.txt")
    val configJson = Json.parse(configFile.str)
    val data = FormTool.vfdbForm.bind(configJson).get
    val seqFile = Tool.getSeqFile(workspaceDir)
    val blast = if (data.seqType == "n") Tool.blastxFile else Tool.blastpFile
    val task = if (data.seqType == "p") "blastp-fast" else "blastx-fast"
    val command =
      s"""
         |${blast.unixPath} -db ${Tool.annoDir.unixPath}/VFDB/VFDB_setB_pro.fas -query seq.fa -out data.xml -task ${task} -evalue ${data.evalue} -outfmt 5 -num_threads 4 -max_target_seqs ${data.maxTargetSeqs}
         |perl ${Tool.annoDir.unixPath}/anno_st/Blast2table -format 10 -xml data.xml -header -top >data.table.xls
         |cp data.table.xls ${resultDir.unixPath}/vfdb.anno.xls
       """.stripMargin
    CommandData(workspaceDir, List(command))
  }

  def phi(workspaceDir: File, resultDir: File) = {
    val configFile = new File(workspaceDir, "config.txt")
    val configJson = Json.parse(configFile.str)
    val data = FormTool.vfdbForm.bind(configJson).get
    val seqFile = Tool.getSeqFile(workspaceDir)
    val blast = if (data.seqType == "n") Tool.blastxFile else Tool.blastpFile
    val task = if (data.seqType == "p") "blastp-fast" else "blastx-fast"
    val command =
      s"""
         |${blast.unixPath} -db ${Tool.annoDir.unixPath}/PHI/PHI.fasta -query seq.fa -out data.xml -task ${task} -evalue ${data.evalue} -outfmt 5 -num_threads 4 -max_target_seqs ${data.maxTargetSeqs}
         |perl ${Tool.annoDir.unixPath}/anno_st/Blast2table -format 10 -xml data.xml -header -top >data.table.xls
         |cp data.table.xls ${resultDir.unixPath}/phi.anno.xls
       """.stripMargin
    CommandData(workspaceDir, List(command))
  }

}
